﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WiimoteLib;
using System.Runtime.InteropServices;

namespace BorderlandsWiimote
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);

        public enum MouseEventFlags
        {
            LEFTDOWN = 0x00000002,
            LEFTUP = 0x00000004,
            MIDDLEDOWN = 0x00000020,
            MIDDLEUP = 0x00000040,
            MOVE = 0x00000001,
            ABSOLUTE = 0x00008000,
            RIGHTDOWN = 0x00000008,
            RIGHTUP = 0x00000010
        } 

        [DllImport("User32.dll")]
        public static extern long SetCursorPos(int x, int y);

        [DllImport("user32.dll", SetLastError = true)]
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
        const int KEYEVENTF_EXTENDEDKEY = 0x1;
        const int KEYEVENTF_KEYUP = 0x2;

        Wiimote wm = new Wiimote();
        private delegate void UpdateWiimoteStateDelegate(WiimoteChangedEventArgs args);

        WiimoteLib.ButtonState previousButtonState;
        WiimoteLib.NunchukState previousNunchuckState;
        WiimoteLib.AccelState previousAccelState;
        WiimoteLib.PointF previousIRPosition;

        bool movingXleft = false;
        bool movingXright = false;
        bool movingYforward = false;
        bool movingYbackward = false;
        bool jumped = false;
        bool hit = false;
        bool reload = false;

        Timer timerIR = new Timer();

        public Form1()
        {
            InitializeComponent();
            timerIR.Tick += new EventHandler(timerIR_Tick);
            timerIR.Interval = 20;
            //timerIR.Start();
        }

        void timerIR_Tick(object sender, EventArgs e)
        {
            #region IR Cursor

            var pos = wm.WiimoteState.IRState.Midpoint;
            int posX = (int)((1 - pos.X) * (Screen.PrimaryScreen.Bounds.Width));
            int posY = (int)(pos.Y * (Screen.PrimaryScreen.Bounds.Height));
            posX = posX - Cursor.Position.X;
            posY = posY - Cursor.Position.Y;

            //int c = (int)Math.Sqrt(Math.Pow(Math.Abs(posX), 2) + Math.Pow(Math.Abs(posY), 2));
            //int pixPerX = c / Math.Abs(posX);
            //int pixPerY = c / Math.Abs(posY);

            //for (int i = 0; i < c; i++)
            //{
            //    mouse_event((uint)MouseEventFlags.MOVE, (uint)(posX > -1 ? pixPerX : -pixPerX), (uint)(posY > -1 ? pixPerY : -pixPerY), 0, 0);
            //}

            mouse_event((uint)MouseEventFlags.MOVE, (uint)((posX > -1 ? 1 : -1) * 3), (uint)((posY > -1 ? 1 : -1) * 3), 0, 0);

            #endregion
        }

        void ReleaseKey(Keys key)
        {
            keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (UIntPtr)0);
        }

        void PressKey(Keys key)
        {
            keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            wm.WiimoteChanged += wm_WiimoteChanged;
            wm.WiimoteExtensionChanged += wm_WiimoteExtensionChanged;
            wm.Connect();
            wm.SetReportType(InputReport.IRAccel, true);
            wm.SetLEDs(false, true, true, false);
            wm.SetReportType(InputReport.IRExtensionAccel, true);
            previousButtonState = wm.WiimoteState.ButtonState;
            previousNunchuckState = wm.WiimoteState.NunchukState;
            previousAccelState = wm.WiimoteState.AccelState;
            previousIRPosition = wm.WiimoteState.IRState.Midpoint;
        }

        private void wm_WiimoteChanged(object sender, WiimoteChangedEventArgs args)
        {
            BeginInvoke(new UpdateWiimoteStateDelegate(UpdateWiimoteChanged), args);
        }

        void UpdateWiimoteChanged(WiimoteChangedEventArgs args)
        {
            var state = args.WiimoteState;

            
            #region Wiimote Buttons

            if (state.ButtonState.Home != previousButtonState.Home)
            {
                if (state.ButtonState.Home)
                {
                    PressKey(Keys.Tab);
                    ReleaseKey(Keys.Tab);
                }
            }

            if (state.ButtonState.B != previousButtonState.B)
            {
                if (state.ButtonState.B) PressKey(Keys.F5);
                else ReleaseKey(Keys.F5);
            }

            if (state.ButtonState.A != previousButtonState.A)
            {
                if (state.ButtonState.B) PressKey(Keys.E);
                else ReleaseKey(Keys.E);
            }

            if (state.ButtonState.Minus != previousButtonState.Minus)
            {
                if (state.ButtonState.Minus)
                {
                    PressKey(Keys.V);
                    ReleaseKey(Keys.V);
                }
            }

            if (state.ButtonState.Plus != previousButtonState.Plus)
            {
                if (state.ButtonState.Plus)
                {
                    PressKey(Keys.D2);
                    ReleaseKey(Keys.D2);
                }
            }
            
            if (state.ButtonState.One != previousButtonState.One)
            {
                if (state.ButtonState.One)
                {
                    PressKey(Keys.D3);
                    ReleaseKey(Keys.D3);
                }
            }

            if (state.ButtonState.Two != previousButtonState.Two)
            {
                if (state.ButtonState.Two)
                {
                    PressKey(Keys.D4);
                    ReleaseKey(Keys.D4);
                }
            }

            #endregion

            #region Nunchuck Buttons
            if (state.NunchukState.Z != previousNunchuckState.Z)
            {
                if (state.NunchukState.Z) PressKey(Keys.F6);
                else ReleaseKey(Keys.F6);
            }
            if (state.NunchukState.C != previousNunchuckState.C)
            {
                if (state.NunchukState.C)
                    PressKey(Keys.F7);
                else ReleaseKey(Keys.F7);
            }
            #endregion


            #region Nuncheck Accel

            if (state.NunchukState.AccelState.Values.X > 0.75)
            {
                if (!movingXright)
                {
                    PressKey(Keys.D);
                    movingXright = true;
                }
            }
            else if (movingXright)
            {
                ReleaseKey(Keys.D);
                movingXright = false;
            }

            if (state.NunchukState.AccelState.Values.X < -0.75)
            {
                if (!movingXleft)
                {
                    PressKey(Keys.A);
                    movingXleft = true;
                }
            }
            else if (movingXleft)
            {
                ReleaseKey(Keys.A);
                movingXleft = false;
            }

            if (state.NunchukState.AccelState.Values.Y < -0.65)
            {
                if (state.NunchukState.Z)
                {
                    PressKey(Keys.F7);
                    ReleaseKey(Keys.F7);
                }
                else if (!movingYbackward)
                {
                    PressKey(Keys.S);
                    movingYbackward = true;
                }
            }
            else if (movingYbackward)
            {
                ReleaseKey(Keys.S);
                movingYbackward = false;
            }

            if (state.NunchukState.AccelState.Values.Y > 0.38)
            {
                if (!movingYforward)
                {
                    PressKey(Keys.W);
                    movingYforward = true;
                }
            }
            else if (movingYforward)
            {
                ReleaseKey(Keys.W);
                movingYforward = false;
            }

            #endregion

            #region Wiimote Accel
            if (state.AccelState.Values.Y < -0.75)
            {
                if (!jumped)
                {
                    PressKey(Keys.Space);
                    jumped = true;
                }
            }
            else if (jumped)
            {
                ReleaseKey(Keys.Space);
                jumped = false;
            }


            if (state.AccelState.Values.X < -0.9)
            {
                if (!reload)
                {
                    PressKey(Keys.R);
                    reload = true;
                }
            }
            else if (reload)
            {
                ReleaseKey(Keys.R);
                reload = false;
            }
            #endregion


            #region AnalogPad

            if (state.ButtonState.Up != previousButtonState.Up)
            {
                if (state.ButtonState.Up) PressKey(Keys.D1);
                else ReleaseKey(Keys.D1);
            }

            if (state.ButtonState.Right != previousButtonState.Right)
            {
                if (state.ButtonState.Right) PressKey(Keys.D2);
                else ReleaseKey(Keys.D2);
            }

            if (state.ButtonState.Left != previousButtonState.Left)
            {
                if (state.ButtonState.Left) PressKey(Keys.D3);
                else ReleaseKey(Keys.D3);
            }

            if (state.ButtonState.Right != previousButtonState.Right)
            {
                if (state.ButtonState.Right) PressKey(Keys.D4);
                else ReleaseKey(Keys.D4);
            }

            #endregion

            #region Joystick

            mouse_event((uint)MouseEventFlags.MOVE, (uint)(state.NunchukState.Joystick.X * 10f), (uint)(-state.NunchukState.Joystick.Y * 10f), 0, 0);

            #endregion


            #region Set Previous States

            previousAccelState = state.AccelState;
            previousButtonState = state.ButtonState;
            previousNunchuckState = state.NunchukState;

            #endregion

        }

        private void wm_WiimoteExtensionChanged(object sender, WiimoteExtensionChangedEventArgs args)
        {
            if (args.Inserted)
                wm.SetReportType(InputReport.IRExtensionAccel, true);
            else
                wm.SetReportType(InputReport.IRAccel, true);
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            wm.Disconnect();
        }

    }
}
